package com.xs.gis.cover.coverImpl;

import com.xs.gis.cover.FileCover;
import com.xs.gis.domain.geojson.GeoCrs;
import com.xs.gis.domain.geojson.GeoCrsProperties;
import com.xs.gis.domain.geojson.GeoFeature;
import com.xs.gis.domain.geojson.GeoJsonFeature;
import com.xs.gis.util.JacksonUtil;
import com.xs.gis.enums.CoverConstant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.store.ContentFeatureCollection;
import org.geotools.data.store.ContentFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @description:
 * @author: w
 * @create: 2023-08-18 10:09
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ShpFileCover implements FileCover {

    /**
     * 字符编码
     */
    private String charSet = StandardCharsets.UTF_8.name();


    @Override
    public String featureToFile(GeoJsonFeature feature, String filePath) {

        try {
            List<GeoFeature> features = feature.getFeatures();

            if (CollectionUtils.isEmpty(features)) {
                throw new RuntimeException("导出的图形数据为null");
            }

            File file = new File(filePath);

            File fileParent = new File(file.getParent());
            if (!fileParent.exists()){
                fileParent.mkdirs();
            }
            Map<String, Serializable> params = new HashMap<>();

            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());

            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);

            GeoFeature geoFeature = features.get(0);
            if(!ObjectUtils.allNotNull(feature.getCrs())){
                GeoCrs geoCrs = new GeoCrs();
                geoCrs.setType("name");
                GeoCrsProperties geoCrsProperties = new GeoCrsProperties();
                geoCrsProperties.setName("EPSG:4490");
                geoCrs.setProperties(geoCrsProperties);
                feature.setCrs(geoCrs);
            }
            String epsg = feature.getEpsg();
            Geometry geometry = geoFeature.formatGeometry();
            // 定义图形信息和属性信息
            SimpleFeatureType simpleFeatureType = builderFeatureType(epsg, geometry, geoFeature);

            ds.setCharset(Charset.forName(charSet));

            ds.createSchema(simpleFeatureType);

            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);

            for (GeoFeature data : features) {
                //写下一条
                SimpleFeature simpleFeature = writer.next();

                simpleFeature.setAttribute(CoverConstant.SHP_GEOM_KEY, data.formatGeometry());

                Map<String, Object> properties = data.getProperties();
                if (Objects.nonNull(properties)) {
                    int i=0;
                    for (String key : properties.keySet()) {
                        Object value = Optional.ofNullable(properties.get(key));
                        simpleFeature.setAttribute(key.length()>8?key.toUpperCase().substring(0,8)+i:key.toUpperCase(), value);
                        i++;
                    }
                }
            }
            writer.write();
            writer.close();
            ds.dispose();
            return filePath;
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (FactoryException e) {
            throw new RuntimeException(e);
        }
    }

    /***
     * 构建表头
     * @param epsg
     * @param geometry
     * @param geoFeature
     * @return
     * @throws FactoryException
     */
    private SimpleFeatureType builderFeatureType(String epsg, Geometry geometry, GeoFeature geoFeature) throws FactoryException {

        //定义图形信息和属性信息
        SimpleFeatureTypeBuilder ftb = new SimpleFeatureTypeBuilder();
        CoordinateReferenceSystem crs = CRS.decode(epsg, true);
        ftb.setCRS(crs);

        ftb.setName("shapefile");
        ftb.add(CoverConstant.SHP_GEOM_KEY,geometry.getClass());

        Map<String, Object> properties = geoFeature.getProperties();

        if (Objects.nonNull(properties)) {
           int i=0;
            for (String key : properties.keySet()) {
                Object value = properties.get(key);
                Class<?> clazz = value.getClass();
                if(clazz.equals(Object.class)){
                    clazz=String.class;
                }
                ftb.add(key.length()>8?key.toUpperCase().substring(0,8)+i:key.toUpperCase(), clazz);
                i++;
            }
        }
        return ftb.buildFeatureType();

    }

    @Override
    public GeoJsonFeature fileToFeature(String filePath) {
        try {
            File shpFile = new File(filePath);
            if (!shpFile.exists() || !shpFile.getPath().endsWith(CoverConstant.SHP_FILE_EXT)) {
                throw new IOException("Invalid shapefile filepath: " + shpFile.getPath());
            }
            // 加载 Shapefile文件
            ShapefileDataStore shapefileDataStore = new ShapefileDataStore(shpFile.toURI().toURL());
            shapefileDataStore.setCharset(Charset.forName(charSet));

            // 所有的信息，不管是.dbf还是.prj的信息都在里面
            ContentFeatureSource featureSource = shapefileDataStore.getFeatureSource();

            // 要素类型定义（类似数据库表结构）
            SimpleFeatureType schema = featureSource.getSchema();

            // 获取 CRS-核心作用是获取地理空间数据的坐标参考系统信息，
            CoordinateReferenceSystem crs = schema.getCoordinateReferenceSystem();
            // 输出 CRS 信息
            System.out.println("EPSG 代码: " + crs.getName());
            System.out.println("WKT 描述: " + crs.toWKT());

            // 是SimpleFeatureCollection接口的实现类，继承自AbstractFeatureCollection，并实现了ContentFeatureSource的要素集合视图。
            ContentFeatureCollection featureCollection = featureSource.getFeatures();
            Writer geoJsonFile = new StringWriter();

            GeometryJSON gjson = new GeometryJSON(15);
            FeatureJSON jSON = new FeatureJSON(gjson);
            jSON.setFeatureType(schema);
            jSON.writeFeatureCollection(featureCollection, geoJsonFile);
            GeoJsonFeature featureDTO = JacksonUtil.toObject(geoJsonFile.toString(), GeoJsonFeature.class);
            return featureDTO;

        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {

            throw new RuntimeException(e);
        }


    }

}
